package linkedlist;

/**
 * @author huangxin
 * @date 2019/6/21-20:45
 */
public class Josepfu {
    public static void main(String[] args) {
        CircleSingleLinkedList linkedList = new CircleSingleLinkedList();
        linkedList.add(5);
        linkedList.showBoys();

        linkedList.josepfu(1, 2,linkedList.getLength());
    }
}

class CircleSingleLinkedList {
    private Boy first;

    /**
     * Josephu  问题为：设编号为1，2，… n的n个人围坐一圈，约定编号为k（1<=k<=n）的人从1开始报数，
     * 数到m 的那个人出列，它的下一位又从1开始报数，数到m的那个人又出列，依次类推，直到所有人出列为止，
     * 由此产生一个出队编号的序列
     * <p>
     * 计算小孩出圈的顺序
     * startno表示从第几个开始数数,countNum表示数多少下,nums表示最初有多少个小孩
     *
     * @param startno
     * @param countNum
     */
    public void josepfu(int startno, int countNum, int nums) {
        //数据校验
        if (first == null || startno < 1 || startno > nums) {
            System.out.println("参数有误");
            return;
        }

        Boy helper = first;
        //获取最后一个元素的指针
        while (true){
            if (helper.getNext() == first){
                break;
            }
            helper = helper.getNext();
        }
        //先让curBoy和helper移动到startno位置,移动startno-1次
        for (int i = 0; i < startno-1; i++) {
            first = first.getNext();
            helper = helper.getNext();
        }
        while (true) {
            //如果圈里只有一个小孩
            if (first == helper) {
                break;
            }
            //移动countNum-1次
            for (int i = 0; i < countNum - 1; i++) {
                first = first.getNext();
                helper = helper.getNext();
            }
            //此时first指向的就是要出圈的小孩
            System.out.printf("出局的小孩编号为:%d\n", first.getNo());
            //让first指向的小孩出圈
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后出局的小孩编号为:%d\n", helper.getNo());

    }

    public void add(int nums) {
        if (nums < 1) {
            System.out.println("nums的值不正确");
            return;
        }
        Boy current  = null;
        for (int i = 1; i <= nums; i++) {
            Boy boy = new Boy(i);
            if (i == 1) {
                //第一次
                first = boy;
                //构成环状
                first.setNext(boy);
                current = boy;
            } else {
                //连接到first构成环状
                boy.setNext(first);
                current.setNext(boy);
                //后移
                current = current.getNext();
            }
        }
    }

    /**
     * 遍历
     */
    public void showBoys() {
        if (first == null) {
            System.out.println("没有任何小孩");
            return;
        }
        Boy temp = first;
        while (true) {
            System.out.printf("小孩的编号:%d\n", temp.getNo());
            //如果下个节点为第一个节点,则表示循环结束
            if (temp.getNext() == first) {
                break;
            }
            temp = temp.getNext();
        }
    }

    public int getLength() {
        if (first == null) {
            System.out.println("链表为空");
            return 0;
        }
        int count = 0;
        Boy temp = first;
        while (true) {
            count++;
            if (temp.getNext() == first) {
                break;
            }
            temp = temp.getNext();
        }
        return count;
    }
}

class Boy {
    private int no;

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public Boy getNext() {
        return next;
    }

    public void setNext(Boy next) {
        this.next = next;
    }

    private Boy next; // 下一个节点

    public Boy(int no) {
        this.no = no;
    }
}
